package no.weather.weatherProxy.wsKlima;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import no.weather.WeatherElement;
import no.weather.WeatherStation;
import no.weather.WeatherType;
import no.weather.misc.IProgress;
import no.weather.weatherProxy.WeatherProxy;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import android.content.Context;
import android.util.Log;

public class WsKlimaProxy implements WeatherProxy {
	public final static String PROVIDER = "Meteorologisk institutt";

	private static final String LOG_ID = "no.weather.weatherProxy.wsKlima.WsKlimaProxy";

	private WsKlimaDatabase db;
	private String mLanguage = "NO";

	public WsKlimaProxy(Context context) {
		db = new WsKlimaDatabase(context);
	}

	public static <T> String list2csl(List<T> l) {
		if (l == null)
			return "";

		String str = l.get(0).toString();
		for (int i = 1; i < l.size(); i++) {
			str += "," + l.get(i).toString();
		}
		return str;
	}

	private void fill(final WeatherType type) {
		try {
			db.fill(type, mLanguage);
		} catch (WeatherTypeNotFoundException e) {
			updateProperies(type.getCode());
			fill(type);
		}
	}

	@Override
	public List<WeatherStation> getAllWeatherStationsFromTimeserie(
			String timeserieID, Boolean includeNotProvidingStations) {
		List<WeatherStation> returnValue = null;
		try {
			URL url = new URL(
					"http://eklima.met.no/metdata/MetDataService?invoke=getStationsFromTimeserieType&timeserietypeID="
							+ timeserieID + "&username=");
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			WeatherStationHandler handler = new WeatherStationHandler(
					includeNotProvidingStations);
			xr.setContentHandler(handler);
			xr.parse(new InputSource(url.openStream()));
			returnValue = handler.getAllStations();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return returnValue;
	}

	public List<WeatherType> getProvidedWeatherType(String id,
			Boolean includeNotProvidingElements) {
		List<WeatherType> types = null;
		try {
			URL url = new URL(
					"http://eklima.met.no/metdata/MetDataService?invoke=getElementsFromTimeserieTypeStation&timeserietypeID=2&stnr="
							+ id);
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			WeatherTypesHandler handler = new WeatherTypesHandler(
					includeNotProvidingElements);
			xr.setContentHandler(handler);
			xr.parse(new InputSource(url.openStream()));
			types = handler.getResult();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return types;
	}

	public List<WeatherElement> getWeather(int timeSerietypeId, Date from,
			Date to, List<String> stations, List<WeatherType> types,
			List<Integer> hours, List<Integer> months, String username) {
		List<String> listOfTypes = new LinkedList<String>();
		for (WeatherType t : types) {
			listOfTypes.add(t.getCode());
		}
		return getWeather(timeSerietypeId, from, to, stations, listOfTypes,
				hours, months, username);
	}

	public List<WeatherElement> getWeather(Integer timeSerietypeId, Date from,
			Date to, List<String> stations, List<String> elements,
			List<Integer> hours, List<Integer> months, String username) {

		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		df.setTimeZone(TimeZone.getTimeZone("gmt"));

		return getWeather(timeSerietypeId.toString(), df.format(from),
				df.format(to), list2csl(stations), list2csl(elements),
				list2csl(hours), list2csl(months), username);
	}

	private List<WeatherElement> getWeather(String timeSerietypeId,
			String from, String to, String stations, String elements,
			String hours, String months, String username) {
		Log.v(LOG_ID, "getting weather, hours:"+hours+" station: "+stations);
		List<WeatherElement> returnValue = null;
		try {
			URL url = new URL(
					"http://eklima.met.no/metdata/MetDataService?invoke=getMetData"
							+ "&timeserietypeID=" + timeSerietypeId
							+ "&format=&from=" + from + "&to=" + to
							+ "&stations=" + stations + "&elements=" + elements
							+ "&hours=" + hours + "&months=" + months
							+ "&username=" + username);

			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			WeatherElementHandler handler = new WeatherElementHandler();
			xr.setContentHandler(handler);
			xr.parse(new InputSource(url.openStream()));
			returnValue = handler.getAllElements();

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(returnValue==null)
		{
			int i = 0;
		}
		for (WeatherElement weatherElement : returnValue) {
			fill(weatherElement.getType());
		}
		return returnValue;
	}

	public List<WeatherElement> getWeather(WeatherStation station, int year,
			int month, int day, Integer hour) {
		Formatter dateFormatter = new Formatter();
		Calendar now = Calendar.getInstance();
		hour -= (now.get(Calendar.ZONE_OFFSET) + now.get(Calendar.DST_OFFSET))
				/ (1000 * 3600);
		if (hour < 0) {
			hour += 24;
			day -= 1;
			if (day < 1) {
				// TODO BÙG !
			}
		}

		String timeSerietypeId = "2";
		String from = dateFormatter.format("%04d-%02d-%02d", year, month, day)
				.toString();
		String to = from;
		String stations = station.getId();
		String elements = station.getTypesCodes();
		String hours = hour.toString();
		String months = "1,2,3,4,5,6,7,8,9,10,11,12";
		String username = "";

		return getWeather(timeSerietypeId, from, to, stations, elements, hours,
				months, username);
	}

	public List<WeatherElement> getWeather(Date from, Date to,
			List<String> stations, List<WeatherType> types) {
		// TODO Get only the hours who are necessary
		/*
		 * //Checks if there is more than 24 hours in difference List<Integer>
		 * hours = null; if((to.getTime()-from.getTime())>24*60*60*1000) { hours
		 * = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
		 * 16, 17, 18, 19, 20, 21, 22, 23); } else if(to.getTime() ==
		 * from.getTime()) { SimpleDateFormat df = new SimpleDateFormat("HH");
		 * df.setTimeZone(TimeZone.getTimeZone("gmt")); hours =
		 * Arrays.asList(new Integer(df.format(to))); } else{
		 * 
		 * }
		 */

		List<Integer> hours = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
				11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23);

		List<Integer> months = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
				12);
		return getWeather(2, from, to, stations, types, hours, months, "");
	}

	public List<WeatherElement> getWeatherNow(WeatherStation station) {
		SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
		date.setTimeZone(TimeZone.getTimeZone("gmt"));
		SimpleDateFormat hourFormat = new SimpleDateFormat("HH");
		hourFormat.setTimeZone(TimeZone.getTimeZone("gmt"));
		Date now = new Date(java.lang.System.currentTimeMillis());

		String timeSerietypeId = "2";
		String from = date.format(now);
		String to = from;
		String stations = station.getId();
		String elements = station.getTypesCodes();
		String hours = hourFormat.format(now);
		String months = "1,2,3,4,5,6,7,8,9,10,11,12";
		String username = "";

		return getWeather(timeSerietypeId, from, to, stations, elements, hours,
				months, username);
	}

	@Override
	public void setLanguage(String language) {
		mLanguage = language;
	}

	/**
	 * Gets the properties from wsKlima and add them to the database
	 * 
	 * @param elementCodes
	 *            Comma separated list with
	 */
	private void updateProperies(String elementCodes) {
		List<WeatherType> types = null;
		try {
			URL url = new URL(
					"http://eklima.met.no/metdata/MetDataService?invoke=getElementsProperties&language="
							+ mLanguage + "&elem_codes=" + elementCodes);
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			WeatherTypesHandler handler = new WeatherTypesHandler(true);
			xr.setContentHandler(handler);
			xr.parse(new InputSource(url.openStream()));
			types = handler.getResult();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (WeatherType t : types) {
			db.add(t, mLanguage);
		}

	}

	/**
	 * @param station
	 * @param progress
	 *            Interface to publish progress between 0 and 1
	 * @param maxAgeInSeconds
	 *            Max age of the data in seconds or maxAgeInSeconds<=0 for any
	 *            age
	 * @return
	 */
	public List<WeatherElement> getWeatherNow(WeatherStation station,
			IProgress progress, Integer maxAgeInSeconds) {
		SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
		date.setTimeZone(TimeZone.getTimeZone("gmt"));
		SimpleDateFormat hourFormat = new SimpleDateFormat("HH");
		hourFormat.setTimeZone(TimeZone.getTimeZone("gmt"));
		long nowMS = java.lang.System.currentTimeMillis();
		Date now = new Date(nowMS);

		String timeSerietypeId = "2";
		String from = date.format(now);
		String stations = station.getId();
		String elements = station.getTypesCodes();
		String hours = hourFormat.format(now);
		String months = "1,2,3,4,5,6,7,8,9,10,11,12";
		String username = "";

		List<WeatherElement> weather = getWeather(timeSerietypeId, from, from,
				stations, elements, hours, months, username);
		long timeMilliSeconds = nowMS;
		while (weather == null || weather.isEmpty()) {
			// Sets back the time an hour:
			timeMilliSeconds -= 3600000;
			if ((nowMS - timeMilliSeconds) > maxAgeInSeconds*1000
					&& maxAgeInSeconds > 0) {
				return null;
			}
			now.setTime(timeMilliSeconds);
			from = date.format(now);
			hours = hourFormat.format(now);
			weather = getWeather(timeSerietypeId, from, from, stations,
					elements, hours, months, username);
		}
		return weather;

	}

}
